/*
	This file is part of Floculate.
	Copyright (C) 2008  Bill Whitacre

	Floculate is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Floculate is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "system.h"

#include <GL/glx.h>
#include <GL/gl.h>
#include <X11/extensions/xf86vmode.h>
#include <X11/keysym.h>

/* stuff about our window grouped together */
typedef struct {
    Display *dpy;
    int screen;
    Window win;
    GLXContext ctx;
    XSetWindowAttributes attr;
    Bool fs;
    XF86VidModeModeInfo deskMode;
    unsigned int width,height;
    unsigned int depth;
    
    rat_key_map *keymap;
    
    char name[2048];
    
    int resizedevent;
    int apptermevent;
    
    float mousex,mousey;
    char buttons[8];
    char keys[256];
} GLWindow;

static int attribs_16bit[]=
{
	GLX_DOUBLEBUFFER,
	GLX_RGBA,
	GLX_RED_SIZE,4,
	GLX_GREEN_SIZE,4,
	GLX_BLUE_SIZE,4,
	GLX_ALPHA_SIZE,4,
	GLX_STENCIL_SIZE,1,
    GLX_DEPTH_SIZE,16,
    None
};

static int attribs_32bit[]=
{
	GLX_DOUBLEBUFFER,
	GLX_RGBA,
	GLX_RED_SIZE,8,
	GLX_GREEN_SIZE,8,
	GLX_BLUE_SIZE,8,
	GLX_ALPHA_SIZE,8,
	GLX_STENCIL_SIZE,1,
    GLX_DEPTH_SIZE,32,
    None
};


GLWindow GLWin;

static void gen_x11_keymap(rat_key_map *keymap) /* Function to create X11 keymap to use. */
{
    rat_key_map_add_pair(keymap,rat_key_pair_create(XK_BackSpace,RAT_KEY_BACK));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Tab,RAT_KEY_TAB));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Linefeed,0)); // ???
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Clear,RAT_KEY_CLEAR));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Return,RAT_KEY_RETURN));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Pause,RAT_KEY_PAUSE));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Scroll_Lock,RAT_KEY_SCROLL));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Sys_Req,0)); // ???
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Escape,RAT_KEY_ESCAPE));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Delete,RAT_KEY_DELETE));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Home,RAT_KEY_HOME));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Left,RAT_KEY_LEFT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Up,RAT_KEY_UP));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Right,RAT_KEY_RIGHT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Down,RAT_KEY_DOWN));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Prior,RAT_KEY_PRIOR));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Page_Up,RAT_KEY_PRIOR));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Next,RAT_KEY_NEXT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Page_Down,RAT_KEY_NEXT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_End,RAT_KEY_END));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Begin,RAT_KEY_HOME));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Space,RAT_KEY_SPACE));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Tab,RAT_KEY_TAB));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Enter,RAT_KEY_RETURN));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_F1,RAT_KEY_F1));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_F2,RAT_KEY_F2));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_F3,RAT_KEY_F3));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_F4,RAT_KEY_F4));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Left,RAT_KEY_LEFT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Up,RAT_KEY_UP));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Right,RAT_KEY_RIGHT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Down,RAT_KEY_DOWN));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Prior,RAT_KEY_PRIOR));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Page_Up,RAT_KEY_PRIOR));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Next,RAT_KEY_NEXT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Page_Down,RAT_KEY_NEXT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_End,RAT_KEY_END));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Begin,RAT_KEY_HOME));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Insert,RAT_KEY_INSERT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Delete,RAT_KEY_DELETE));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Equal,0)); // ???
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Multiply,RAT_KEY_MULTIPLY));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Add,RAT_KEY_ADD));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Separator,RAT_KEY_SEPARATOR));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Subtract,RAT_KEY_SUBTRACT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Decimal,RAT_KEY_DECIMAL));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_Divide,RAT_KEY_DIVIDE));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_0,RAT_KEY_KEY_0));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_1,RAT_KEY_KEY_1));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_2,RAT_KEY_KEY_2));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_3,RAT_KEY_KEY_3));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_4,RAT_KEY_KEY_4));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_5,RAT_KEY_KEY_5));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_6,RAT_KEY_KEY_6));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_7,RAT_KEY_KEY_7));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_8,RAT_KEY_KEY_8));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_KP_9,RAT_KEY_KEY_9));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F1,RAT_KEY_F1));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F2,RAT_KEY_F2));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F3,RAT_KEY_F3));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F4,RAT_KEY_F4));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F5,RAT_KEY_F5));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F6,RAT_KEY_F6));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F7,RAT_KEY_F7));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F8,RAT_KEY_F8));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F9,RAT_KEY_F9));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F10,RAT_KEY_F10));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F11,RAT_KEY_F11));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F12,RAT_KEY_F12));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Shift_L,RAT_KEY_LSHIFT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Shift_R,RAT_KEY_RSHIFT));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Control_L,RAT_KEY_LCONTROL));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Control_R,RAT_KEY_RCONTROL));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Caps_Lock,RAT_KEY_CAPITAL));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Shift_Lock,RAT_KEY_CAPITAL));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Meta_L,RAT_KEY_LSUPER));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Meta_R,RAT_KEY_RSUPER));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Alt_L,RAT_KEY_LMENU));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Alt_R,RAT_KEY_RMENU));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_ISO_Level3_Shift,RAT_KEY_RMENU));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Menu,RAT_KEY_MENU));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_space,RAT_KEY_SPACE));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_exclam,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_quotedbl,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_section,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_numbersign,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_question,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_at,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_mu,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_EuroSign,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_A,RAT_KEY_KEY_A));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_B,RAT_KEY_KEY_B));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_C,RAT_KEY_KEY_C));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_D,RAT_KEY_KEY_D));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_E,RAT_KEY_KEY_E));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_F,RAT_KEY_KEY_F));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_G,RAT_KEY_KEY_G));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_H,RAT_KEY_KEY_H));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_I,RAT_KEY_KEY_I));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_J,RAT_KEY_KEY_J));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_K,RAT_KEY_KEY_K));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_L,RAT_KEY_KEY_L));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_M,RAT_KEY_KEY_M));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_N,RAT_KEY_KEY_N));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_O,RAT_KEY_KEY_O));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_P,RAT_KEY_KEY_P));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Q,RAT_KEY_KEY_Q));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_R,RAT_KEY_KEY_R));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_S,RAT_KEY_KEY_S));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_T,RAT_KEY_KEY_T));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_U,RAT_KEY_KEY_U));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_V,RAT_KEY_KEY_V));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_W,RAT_KEY_KEY_W));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_X,RAT_KEY_KEY_X));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Y,RAT_KEY_KEY_Y));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Z,RAT_KEY_KEY_Z));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Adiaeresis,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Odiaeresis,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_Udiaeresis,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_bracketleft,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_backslash,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_bracketright,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_asciicircum,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_degree,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_underscore,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_grave,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_acute,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_quoteleft,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_a,RAT_KEY_KEY_A));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_b,RAT_KEY_KEY_B));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_c,RAT_KEY_KEY_C));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_d,RAT_KEY_KEY_D));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_e,RAT_KEY_KEY_E));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_f,RAT_KEY_KEY_F));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_g,RAT_KEY_KEY_G));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_h,RAT_KEY_KEY_H));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_i,RAT_KEY_KEY_I));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_j,RAT_KEY_KEY_J));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_k,RAT_KEY_KEY_K));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_l,RAT_KEY_KEY_L));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_m,RAT_KEY_KEY_M));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_n,RAT_KEY_KEY_N));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_o,RAT_KEY_KEY_O));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_p,RAT_KEY_KEY_P));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_q,RAT_KEY_KEY_Q));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_r,RAT_KEY_KEY_R));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_s,RAT_KEY_KEY_S));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_t,RAT_KEY_KEY_T));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_u,RAT_KEY_KEY_U));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_v,RAT_KEY_KEY_V));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_w,RAT_KEY_KEY_W));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_x,RAT_KEY_KEY_X));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_y,RAT_KEY_KEY_Y));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_z,RAT_KEY_KEY_Z));
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_ssharp,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_adiaeresis,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_odiaeresis,0)); //?
	rat_key_map_add_pair(keymap,rat_key_pair_create(XK_udiaeresis,0)); //?
	rat_key_map_sort(keymap);
}

int rat_start_system_core(char *name,unsigned int vw,
	unsigned int vh,unsigned int vbpp,int vfs)
{
	XVisualInfo *vi;
    Colormap cmap;
    int dpyWidth, dpyHeight;
    int i;
    int glxMajorVersion, glxMinorVersion;
    int vidModeMajorVersion, vidModeMinorVersion;
    XF86VidModeModeInfo **modes;
    int modeNum;
    int bestMode;
    Atom wmDelete;
    Window winDummy;
    unsigned int borderDummy;
    int dummy_x,dummy_y;
    
    memset(&GLWin,0,sizeof(GLWindow));
    strcpy(GLWin.name,name);
    
    GLWin.keymap=rat_key_map_create();
    gen_x11_keymap(GLWin.keymap);
    
    GLWin.fs=vfs;
    /* set best mode to current */
    bestMode=0;
    /* get a connection */
    GLWin.dpy = XOpenDisplay(0);
    GLWin.screen = DefaultScreen(GLWin.dpy);
    XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion,
        &vidModeMinorVersion);
    printf("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion,
        vidModeMinorVersion);
    XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes);
    /* save desktop-resolution before switching modes */
    GLWin.deskMode = *modes[0];
    /* look for mode with requested resolution */
    for (i = 0; i < modeNum; i++)
    {
        if ((modes[i]->hdisplay == vw) && (modes[i]->vdisplay == vh))
        {
            bestMode = i;
        }
    }
    /* get an appropriate visual */
    switch (vbpp)
    {
    case 16:
    case 24:
    	vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attribs_16bit);
		if (vi == NULL) return 0;
		break;
   	case 32:
		vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attribs_32bit);
		if (vi == NULL) return 0;
		break;
    }
    
    glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion);
    printf("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion);
    /* create a GLX context */
    GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE);
    /* create a color map */
    cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
        vi->visual, AllocNone);
    GLWin.attr.colormap = cmap;
    GLWin.attr.border_pixel = 0;

    if (GLWin.fs)
    {
        XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]);
        XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
        dpyWidth = modes[bestMode]->hdisplay;
        dpyHeight = modes[bestMode]->vdisplay;
        printf("Resolution %dx%d\n", dpyWidth, dpyHeight);
        XFree(modes);
    
        /* create a fullscreen window */
        GLWin.attr.override_redirect=1;
        GLWin.attr.event_mask=ExposureMask|VisibilityChangeMask|KeyPressMask|
            KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|
            StructureNotifyMask|SubstructureNotifyMask|FocusChangeMask;
        GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
            0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
            CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
            &GLWin.attr);
        XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0);
		XMapRaised(GLWin.dpy, GLWin.win);
        XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync,
            GrabModeAsync, CurrentTime);
        XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask,
            GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime);
    }
    else
    {
        /* create a window in window mode*/
        GLWin.attr.override_redirect=1;
        GLWin.attr.event_mask=ExposureMask|VisibilityChangeMask|KeyPressMask|
            KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|
            StructureNotifyMask|SubstructureNotifyMask|FocusChangeMask;
        GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
            0, 0, vw, vh, 0, vi->depth, InputOutput, vi->visual,
            CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr);
        /* only set window title and handle wm_delete_events if in windowed mode */
        wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True);
        XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1);
        XSetStandardProperties(GLWin.dpy, GLWin.win, name,
            name, None, NULL, 0, NULL);
        XMapRaised(GLWin.dpy, GLWin.win);
    }       
    /* connect the glx-context to the window */
    glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
    XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &dummy_x, &dummy_y,
        &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
    printf("Depth %d\n", GLWin.depth);
    if (glXIsDirect(GLWin.dpy, GLWin.ctx)) 
        printf("Super happy direct rendering time!\n");
    else
        printf("Sorry, no direct rendering possible!\n");

    return 1;
}

void rat_stop_system_core()
{
	rat_key_map_destroy(GLWin.keymap);
	if (GLWin.ctx)
    {
        if (!glXMakeCurrent(GLWin.dpy, None, NULL))
            printf("Could not release drawing context.\n");
        else
        	printf("released drawing context.\n");
        glXDestroyContext(GLWin.dpy, GLWin.ctx);
        GLWin.ctx = NULL;
    }
    /* switch back to original desktop resolution if we were in fs */
    if (GLWin.fs)
    {
        XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode);
        XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
        printf("Restored video mode.\n");
    }
    XCloseDisplay(GLWin.dpy);
}

int rat_handle_events()
{
	XEvent event;
	rat_key_map *keymap;
    RAT_SYS_KEY vkey;
    RAT_KEY_CODE mkey;

	/* handle the events in the queue */
    while (XPending(GLWin.dpy)>0)
    {
        XNextEvent(GLWin.dpy,&event);
        switch (event.type)
        {
            case Expose:
                if (event.xexpose.count!=0) break;
     	        break;
            case ConfigureNotify:
                if ((event.xconfigure.width!=GLWin.width) || 
                    (event.xconfigure.height!=GLWin.height))
                {
                    GLWin.width=event.xconfigure.width;
                    GLWin.height=event.xconfigure.height;
                    GLWin.resizedevent=1;
                }
                break;
            case ClientMessage:
                if (*XGetAtomName(GLWin.dpy, event.xclient.message_type) == 
                    *"WM_PROTOCOLS")
                {
                    printf("Terminate WM signal...\n");
                    GLWin.apptermevent=1;
                }
                break;
           	case KeyRelease:
		        /* Key released */
		        vkey=XKeycodeToKeysym(GLWin.dpy,event.xkey.keycode,0);
		        keymap=GLWin.keymap;
		        mkey=rat_key_map_get_code(keymap,vkey);

		        if (mkey)
		            GLWin.keys[mkey]=0;
		        else
		            GLWin.keys[vkey]=0;

		        break;
            case KeyPress:
		        /* Key pressed */
		        vkey=XKeycodeToKeysym(GLWin.dpy,event.xkey.keycode,0);
		        keymap=GLWin.keymap;
		        mkey=rat_key_map_get_code(keymap,vkey);

		        if (mkey)
		            GLWin.keys[mkey]=1;
		        else
		            GLWin.keys[vkey]=1;

		        break;
			case ButtonRelease:
		        /* Mouse button released */
		        GLWin.buttons[event.xbutton.button-1]=0;
		        break;
		    case ButtonPress:
		        /* Mouse button pressed */
		        GLWin.buttons[event.xbutton.button-1]=1;
		        break;
		    case MotionNotify:
		        /* Mouse moved */
		        GLWin.mousex=(double)event.xmotion.x/(double)GLWin.width;
				GLWin.mousey=(double)event.xmotion.y/(double)GLWin.height;
		        break;
            default:
                break;
        }
    }
}

void rat_video_size(unsigned int *vw,unsigned int *vh)
{
	*vw=GLWin.width;
	*vh=GLWin.height;
}

int rat_update_video()
{
	glXSwapBuffers(GLWin.dpy,GLWin.win);
	return 1;
}

void rat_get_mouse_position(float *x,float *y)
{
	*x=GLWin.mousex;
	*y=GLWin.mousey;
}

int rat_is_key_down(RAT_KEY_CODE key)
{
	return GLWin.keys[key];
}

int rat_is_mouse_down(int button)
{
	return GLWin.buttons[button];
}

int rat_appterm_event()
{
	return GLWin.apptermevent;
}

int rat_resized_event()
{
	return GLWin.resizedevent;
}

